package com.rxt.thermopro.viewmodel

import android.annotation.SuppressLint
import android.bluetooth.*
import android.os.Build
import android.util.Log
import android.view.View
import androidx.core.content.ContextCompat
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.app.common.ex.logD
import com.app.common.viewmodel.BaseViewModel
import com.app.common.viewmodel.EventLiveData
import com.rxt.ble.BleManager
import com.rxt.ble.callback.BleGattCallback
import com.rxt.ble.callback.BleNotifyCallback
import com.rxt.ble.callback.BleWriteCallback
import com.rxt.ble.data.BleDevice
import com.rxt.ble.exception.BleException
import com.rxt.ble.utils.HexUtil
import com.rxt.thermopro.adapter.DeviceListAdapter
import com.rxt.thermopro.app.AppContext
import com.rxt.thermopro.app.LocalDataDao
import com.rxt.thermopro.bean.*
import com.rxt.thermopro.ex.MyLineRegression
import com.rxt.thermopro.ex.UuidConsts
import kotlinx.coroutines.*
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.LinkedHashMap

class BleMessageViewModel : BaseViewModel() {

    companion object {
        const val BLUETOOTH_SERVICE_UUID = "0000fff0-0000-1000-8000-00805f9b34fb"
        const val BLUETOOTH_NOTIFY_UUID = "0000fff2-0000-1000-8000-00805f9b34fb"
        const val BLUETOOTH_WRITE_UUID = "0000fff1-0000-1000-8000-00805f9b34fb"

        const val BLUETOOTH_SERVICE_UUID_960 = "93bb7cab-eb14-c5a9-2354-a24f4df9330f"
        const val BLUETOOTH_NOTIFY_UUID_960 = "0000ff01-0000-1000-8000-00805f9b34fb"
        const val BLUETOOTH_WRITE_UUID_960 = "0000ff02-0000-1000-8000-00805f9b34fb"


        const val BLUETOOTH_SERVICE_UUID_359 = "00010203-0405-0607-0809-0a0b0c0d1910"
        const val BLUETOOTH_NOTIFY_UUID_359 = "00010203-0405-0607-0809-0a0b0c0d2b10"
        const val BLUETOOTH_WRITE_UUID_359 = "00010203-0405-0607-0809-0a0b0c0d2b11"


        const val DEVICE_TYPE_BBQ = 1
        const val DEVICE_TYPE_GRILL = 2
        const val DEVICE_TYPE_TP960 = 3
        const val DEVICE_TYPE_TP359 = 4

    }


    val notifyMsgData: EventLiveData<HashMap<Long, MutableList<ProbeBean>>> = EventLiveData()
    val notifyRefreshTempData: MutableLiveData<MutableList<ProbeBean>> = MutableLiveData()
    val notifyHistoryTempData: EventLiveData<Map<String, MutableList<ProbeHistoryBean>>> =
        EventLiveData()
    val notifyInfoData: EventLiveData<DeviceInfoBean> = EventLiveData()
    val signalLevel: EventLiveData<HashMap<Long, LinkedHashMap<String, Int>>> = EventLiveData()
    val signalLevelNoConnect: EventLiveData<HashMap<Long, LinkedHashMap<String, Int>>> =
        EventLiveData()
    val signalLevelCache = LinkedHashMap<String, Int>()
    val connectSuccess: EventLiveData<LinkedHashMap<String, Long>> = EventLiveData()
    val reConnectSuccess: EventLiveData<HashMap<String, Long>> = EventLiveData()
    val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm")

    //    val cacheMsgData = mutableListOf<ProbeBean>()
    val cacheMsgData = hashMapOf<String, MutableList<ProbeBean>>()
    val disconnectData: EventLiveData<Pair<String, Long>> = EventLiveData()
    val disconnectForeverData: MutableLiveData<Pair<String, String>> = MutableLiveData()
    val loadCacheData: EventLiveData<Long> = EventLiveData()

    val notifyMsgDataCache = hashMapOf<String, MutableList<ProbeBean>>()
    val notifyInfoDataCache = mutableListOf<Pair<String, DeviceInfoBean>>()


    //    val notifyTP960ProbeStatus: EventLiveData<HashMap<String, Pair<Int, Int>>> = EventLiveData()
    val notifyTP960ProbeStatusForever: MutableLiveData<HashMap<String, Pair<Int, Int>>> =
        MutableLiveData()
    val notifyTP960AlarmClose: MutableLiveData<HashMap<String, Pair<Long, Int>>> = MutableLiveData()
    val notifyTP960BoxBattery: EventLiveData<HashMap<String, Int>> = EventLiveData()
    val notifyTP960ProbeBattery: EventLiveData<HashMap<String, Pair<Int, Float>>> = EventLiveData()
    val notifyHistoryTempTP960Data: EventLiveData<HashMap<Int, MutableList<TempBean>>> =
        EventLiveData()
    val sbStringTP960 = StringBuffer()

    //    val liveDataMerger: MediatorLiveData<Pair<String, Long>> =  MediatorLiveData()
    val disconnectTP960ForeverData: MutableLiveData<Pair<String, Long>> = MutableLiveData()

    //预测时间
    val probeTempComputeTime: MutableLiveData<Pair<Long, HashMap<String, String>>> =
        MutableLiveData()

    //后台重连service
    val reConnectService: EventLiveData<Long> = EventLiveData()

    val otaUploadStatus: EventLiveData<HashMap<String, Pair<Long, Int>>> = EventLiveData()
    val otaControl:EventLiveData<HashMap<String, Pair<Long, Int>>> = EventLiveData()

    @Volatile
    var totalLength = 0

    @Volatile
    var receiveSize = 0

    val tempListCache = hashMapOf<String, MutableList<TempBean>>()
    val connectedDeviceList = mutableListOf<BleDevice>()

    val notifyHistoryTempTP359Data: EventLiveData<HashMap<Int, MutableList<TempHumBean>>> =
        EventLiveData()

    init {
//        liveDataMerger.addSource(disconnectTP960ForeverData){
//            liveDataMerger.postValue(it)
//        }
//        liveDataMerger.addSource(notifyTP960ProbeStatus){
//            val address=it.keys.last()
//            liveDataMerger.postValue(address to System.currentTimeMillis())
//        }
        startAddNewTempToHistory()
        startComputeHistory()
        LocalDataDao.INSTANCE.startSaveHistory()
    }

    private fun clearCache(macAddress: String) {
        notifyMsgDataCache.remove(macAddress)
        notifyInfoDataCache.clear()
        cacheMsgData.remove(macAddress)
        signalLevelCache.remove(macAddress)
    }

    fun connectBleList(deviceList: MutableList<DeviceBean>) {
        viewModelScope.launch {
            for (i in 0 until deviceList.size) {
                if (deviceList[i].name?.contains("bbq", true) == false &&
                    deviceList[i].name?.contains("tp960r", true) == false &&
                    deviceList[i].name?.contains("grill", true) == false &&
                    deviceList[i].name?.contains("tp359", true) == false
                ) {
                    continue
                }
                val list =
                    BleManager.getInstance().allConnectedDevice.filter { it.mac == deviceList[i].address }
                if (list.isNotEmpty()) {
                    continue
                }
                val address = deviceList[i].address
                // 开始连接
                BleManager.getInstance().connect(address, object : BleGattCallback() {
                    override fun onStartConnect() {

                    }

                    override fun onConnectFail(bleDevice: BleDevice, exception: BleException) {
                        // 连接失败
                        logD(" 蓝牙连接失败原因${exception.toString()}")
                        stopGetTemp(bleDevice.mac)
                        viewModelScope.launch {
                            withContext(Dispatchers.Main) {
                                BleManager.getInstance().disconnect(bleDevice)
                            }
                        }
                    }

                    override fun onConnectSuccess(
                        bleDevice: BleDevice,
                        gatt: BluetoothGatt,
                        status: Int
                    ) {
                        // 连接成功，BleDevice即为所连接的BLE设备
                        logD(" connectBleList蓝牙连接成功${bleDevice.mac}  ${bleDevice.name}")
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                            BleManager.getInstance().getBluetoothGatt(bleDevice).setPreferredPhy(
                                BluetoothDevice.PHY_LE_CODED,
                                BluetoothDevice.PHY_LE_CODED,
                                BluetoothDevice.PHY_OPTION_S8
                            )
                        }
                        connectedDeviceList.add(bleDevice)
                        //连接停止报警
                        AppContext.get().stopAlarm(bleDevice.mac)
                        reConnectSuccess.postValue(hashMapOf<String, Long>().apply {
                            this[bleDevice.mac] = System.currentTimeMillis()
                        })

                        deviceList.forEach {
                            if (bleDevice.mac == it.address) {
                                when {
                                    it.name?.contains("bbq", true) == true -> {
                                        logD(" connectBleList  bbq ->${bleDevice.mac}  ${bleDevice.rssi}")
                                        signalLevelCache[bleDevice.mac] = bleDevice.rssi
                                        signalLevel.value =
                                            hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                                this[System.currentTimeMillis()] = signalLevelCache
                                            }
                                        notifyBBQDevice(bleDevice)
                                    }
                                    it.name?.contains("tp960", true) == true -> {
                                        logD(" connectBleList  tp960 ->${bleDevice.mac}  ${bleDevice.rssi}")
                                        signalLevelCache[bleDevice.mac] = bleDevice.rssi
                                        signalLevel.value =
                                            hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                                this[System.currentTimeMillis()] = signalLevelCache
                                            }
                                        notifyTP960Device(bleDevice)
                                    }
                                    it.name?.contains("grill", true) == true -> {
                                        logD(" connectBleList  grill ->${bleDevice.mac}  ${bleDevice.rssi}")
                                        signalLevelCache[bleDevice.mac] = bleDevice.rssi
                                        signalLevel.value =
                                            hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                                this[System.currentTimeMillis()] = signalLevelCache
                                            }
                                        notifyBBQDevice(bleDevice)
                                    }
                                    it.name?.contains("tp359", true) == true -> {
                                        logD(" connectBleList  tp359 ->${bleDevice.mac}  ${bleDevice.rssi}")
                                        signalLevelCache[bleDevice.mac] = bleDevice.rssi
                                        signalLevel.value =
                                            hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                                this[System.currentTimeMillis()] = signalLevelCache
                                            }
                                        notifyTP359Device(bleDevice)
                                    }
                                }
                            }
                        }
                    }

                    override fun onDisConnected(
                        isActiveDisConnected: Boolean,
                        bleDevice: BleDevice,
                        gatt: BluetoothGatt,
                        status: Int
                    ) {
                        // 连接中断，isActiveDisConnected表示是否是主动调用了断开连接方法
                        BleManager.getInstance().disconnect(bleDevice)
                        connectedDeviceList.remove(bleDevice)
                        if (LocalDataDao.INSTANCE.isDisconnectNotice(bleDevice.mac) && !isActiveDisConnected) {

                            disconnectData.postValue(bleDevice.mac to System.currentTimeMillis())
                            disconnectForeverData.postValue(
                                bleDevice.mac to System.currentTimeMillis().toString() + "_$status"
                            )
                        }
                        clearCache(bleDevice.mac)
                        stopGetTemp(bleDevice.mac)
                    }

                    override fun onReadRemoteRssi(gatt: BluetoothGatt?, rssi: Int, status: Int) {
                        super.onReadRemoteRssi(gatt, rssi, status)
                        gatt?.device?.address?.let {
                            signalLevelCache[it] = rssi
                            signalLevel.postValue(hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                this[System.currentTimeMillis()] = signalLevelCache
                            })

                        }
                    }

                    override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
                        super.onServicesDiscovered(gatt, status)
                        if (status == 0) {
                            var ota_mode=false
                            val boolOTAbegin=true
                            //REFRESH SERVICES UI <- REFRESH SERVICES MENU BUTTON
                            //DEFINE IF DEVICE SUPPORT OTA & MODE (NORMAL/DFU)
                            val otaServiceCheck = gatt?.getService(UuidConsts.OTA_SERVICE) != null
                            if (otaServiceCheck) {
                                val otaDataCheck =
                                    gatt?.getService(UuidConsts.OTA_SERVICE)?.getCharacteristic(
                                        UuidConsts.OTA_DATA
                                    ) != null
                                if (otaDataCheck) {
                                    val homekitCheck =
                                        gatt?.getService(UuidConsts.HOMEKIT_SERVICE) != null
                                    if (!homekitCheck) {
                                        ota_mode = true
                                        val otaDataProperty =
                                            gatt?.getService(UuidConsts.OTA_SERVICE)
                                                ?.getCharacteristic(
                                                    UuidConsts.OTA_DATA
                                                )?.properties
                                        if ((otaDataProperty == 12) || (otaDataProperty == 8) || (otaDataProperty == 10)) {
                                            //reliable = true;
                                        } else if (ota_mode && otaDataProperty == 4) {
                                            //reliable = false;
                                        }
                                    }
                                }
                            }
                            gatt?.let {
                                otaUploadStatus.postValue(hashMapOf<String, Pair<Long, Int>>().apply {
                                    val otaStatus=if (ota_mode) 1 else 0
                                    this[it.device.address]=System.currentTimeMillis() to otaStatus
                                })
                            }

                            //REQUEST MTU
//                            if (UICreated && loadingdialog?.isShowing!!) {
//                                bluetoothGatt?.requestMtu(MTU)
//                            }

                            //LAUNCH SERVICES UI
//                            if (!boolFullOTA) {
//                                handler.postDelayed({
//                                    runOnUiThread {
//                                        onGattFetched()
//                                        hideCharacteristicLoadingAnimation()
//                                    }
//                                }, GATT_FETCH_ON_SERVICE_DISCOVERED_DELAY.toLong())
//                            }

                            //IF DFU_MODE, LAUNCH OTA SETUP AUTOMATICALLY
                            if (ota_mode && boolOTAbegin) {
//                                handler.postDelayed({
//                                    runOnUiThread {
//                                        loadingimage?.visibility = View.GONE
//                                        loadingdialog?.dismiss()
//                                        showOtaProgress()
//                                    }
//                                }, (2.5 * UI_CREATION_DELAY).toLong())
                            }
                        }
                    }

                    override fun onCharacteristicWrite(
                        gatt: BluetoothGatt?,
                        characteristic: BluetoothGattCharacteristic?,
                        status: Int
                    ) {
                        super.onCharacteristicWrite(gatt, characteristic, status)
                        if (status==0){
                            if ((characteristic?.uuid == UuidConsts.OTA_CONTROL)) { //OTA Control Callback Handling
                                if (characteristic.value.size == 1) {
                                    if (characteristic.value[0] == 0x00.toByte()) {
//                                        Timber.d("Callback: Control %s, status = %d",
//                                            Converters.bytesToHexWhitespaceDelimited(characteristic.value), status)
                                        gatt?.let {
                                            otaControl.postValue(hashMapOf<String, Pair<Long, Int>>().apply {
                                                this[it.device.address]=System.currentTimeMillis() to 0
                                            })
                                        }
                                    }
                                    if (characteristic.value[0] == 0x03.toByte()) {
                                        gatt?.let {
                                            otaControl.postValue(hashMapOf<String, Pair<Long, Int>>().apply {
                                                this[it.device.address]=System.currentTimeMillis() to 3
                                            })
                                        }
                                    }
                                } else {
//                                    Timber.i("OTA_Control: received: %s",
//                                        Converters.bytesToHexWhitespaceDelimited(characteristic.value)
//                                    )
                                    if (characteristic.value[0] == 0x00.toByte() && characteristic.value[1] == 0x02.toByte()) {
//                                        Timber.i("HomeKit: reading OTA_Control...")
                                        gatt?.readCharacteristic(characteristic)
                                    }
                                }
                            }
                            if ((characteristic?.uuid == UuidConsts.OTA_DATA)) {   //OTA Data Callback Handling
                                //todo
                                gatt?.let {
                                    otaControl.postValue(hashMapOf<String, Pair<Long, Int>>().apply {
                                        this[it.device.address]=System.currentTimeMillis() to 4
                                    })
                                }
                            }
                        }
                    }
                })
                delay(2000)
            }
        }
    }

    /**
     * 连接蓝牙接收通知
     */
    fun connectBluetooth(bean: ProbeBean) {
        val address = bean.address
        if (!bean.name.contains("bbq", true) &&
            !bean.name.contains("tp960r", true) &&
            !bean.name.contains("grill", true) &&
            !bean.name.contains("tp359", true)
        ) {
            return
        }

        val list = BleManager.getInstance().allConnectedDevice.filter { it.mac == address }
        if (list.isNotEmpty()) {
            logD("蓝牙已连接  不需要再次连接${address}")
            loadCacheData.postValue(System.currentTimeMillis())
            if (notifyMsgDataCache.containsKey(address)) {
                notifyMsgData.value = hashMapOf<Long, MutableList<ProbeBean>>().apply {
                    this[System.currentTimeMillis()] = mutableListOf<ProbeBean>().apply {
                        this.addAll(notifyMsgDataCache[address] ?: emptyList())
                    }
                }
            }
            signalLevelNoConnect.value =
                hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                    this[System.currentTimeMillis()] = linkedMapOf<String, Int>().apply {
                        this[address] = 0
                    }
                }
            when {
                bean.name.contains("bbq", true) -> {
                    getDeviceInfo(list.first())
                }
                bean.name.contains("tp960", true) -> {
                    connectSuccess.value = linkedMapOf<String, Long>().apply {
                        this[address] = System.currentTimeMillis()
                    }
                }
                bean.name.contains("grill", true) -> {
                    getDeviceInfo(list.first())
                }
                bean.name.contains("tp359", true) -> {
                    connectSuccess.value = linkedMapOf<String, Long>().apply {
                        this[address] = System.currentTimeMillis()
                    }
                }
            }
            return
        }
        // 开始连接
        BleManager.getInstance().connect(address, object : BleGattCallback() {
            override fun onStartConnect() {

            }

            override fun onConnectFail(bleDevice: BleDevice, exception: BleException) {
                // 连接失败
                logD(" 蓝牙连接失败原因${exception.toString()}")
                stopGetTemp(bleDevice.mac)
                viewModelScope.launch {
                    withContext(Dispatchers.Main) {
                        BleManager.getInstance().disconnect(bleDevice)
                    }
                }
            }

            override fun onConnectSuccess(
                bleDevice: BleDevice,
                gatt: BluetoothGatt,
                status: Int
            ) {
                // 连接成功，BleDevice即为所连接的BLE设备
                logD(" 蓝牙连接成功${bleDevice.mac}  ${bleDevice.name}  rssi=${bleDevice.rssi} ")
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    BleManager.getInstance().getBluetoothGatt(bleDevice).setPreferredPhy(
                        BluetoothDevice.PHY_LE_CODED,
                        BluetoothDevice.PHY_LE_CODED,
                        BluetoothDevice.PHY_OPTION_S8
                    )
                }
                connectedDeviceList.add(bleDevice)
                //连接停止报警
                AppContext.get().stopAlarm(bleDevice.mac)
                reConnectSuccess.postValue(hashMapOf<String, Long>().apply {
                    this[bleDevice.mac] = System.currentTimeMillis()
                })

                if (bleDevice.mac == address) {
                    when {
                        bean.name.contains("bbq", true) -> {
                            logD(" connectBleList  bbq ->${bleDevice.mac}  ${bleDevice.rssi}")
                            signalLevelCache[bleDevice.mac] = bleDevice.rssi
                            signalLevel.value =
                                hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                    this[System.currentTimeMillis()] = signalLevelCache
                                }
                            notifyBBQDevice(bleDevice)
                        }
                        bean.name.contains("tp960", true) -> {
                            logD(" connectBleList  tp960 ->${bleDevice.mac}  ${bleDevice.rssi}")
                            signalLevelCache[bleDevice.mac] = bleDevice.rssi
                            signalLevel.value =
                                hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                    this[System.currentTimeMillis()] = signalLevelCache
                                }
                            notifyTP960Device(bleDevice)
                        }
                        bean.name.contains("grill", true) -> {
                            logD(" connectBleList  grill ->${bleDevice.mac}  ${bleDevice.rssi}")
                            signalLevelCache[bleDevice.mac] = bleDevice.rssi
                            signalLevel.value =
                                hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                    this[System.currentTimeMillis()] = signalLevelCache
                                }
                            notifyBBQDevice(bleDevice)
                        }
                        bean.name.contains("tp359", true) -> {
                            logD(" connectBleList  tp359 ->${bleDevice.mac}  ${bleDevice.rssi}")
                            signalLevelCache[bleDevice.mac] = bleDevice.rssi
                            signalLevel.value =
                                hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                                    this[System.currentTimeMillis()] = signalLevelCache
                                }
                            notifyTP359Device(bleDevice)
                        }
                    }
                }
            }

            override fun onDisConnected(
                isActiveDisConnected: Boolean,
                bleDevice: BleDevice,
                gatt: BluetoothGatt,
                status: Int
            ) {
                // 连接中断，isActiveDisConnected表示是否是主动调用了断开连接方法
                BleManager.getInstance().disconnect(bleDevice)
                connectedDeviceList.remove(bleDevice)
                if (LocalDataDao.INSTANCE.isDisconnectNotice(bleDevice.mac) &&
                    !isActiveDisConnected
                ) {
                    disconnectData.postValue(bleDevice.mac to System.currentTimeMillis())
                    disconnectForeverData.postValue(
                        bleDevice.mac to
                                System.currentTimeMillis().toString() + "_$status"
                    )
                }
                clearCache(bleDevice.mac)
                stopGetTemp(bleDevice.mac)
            }

            override fun onReadRemoteRssi(gatt: BluetoothGatt?, rssi: Int, status: Int) {
                super.onReadRemoteRssi(gatt, rssi, status)
                gatt?.device?.address?.let {
                    signalLevelCache[it] = rssi
                    signalLevel.postValue(hashMapOf<Long, LinkedHashMap<String, Int>>().apply {
                        this[System.currentTimeMillis()] = signalLevelCache
                    })
                }
            }

            override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
                super.onServicesDiscovered(gatt, status)
                if (status == 0) {
                    var ota_mode=false
                    val boolOTAbegin=true
                    //REFRESH SERVICES UI <- REFRESH SERVICES MENU BUTTON
                    //DEFINE IF DEVICE SUPPORT OTA & MODE (NORMAL/DFU)
                    val otaServiceCheck = gatt?.getService(UuidConsts.OTA_SERVICE) != null
                    if (otaServiceCheck) {
                        val otaDataCheck =
                            gatt?.getService(UuidConsts.OTA_SERVICE)?.getCharacteristic(
                                UuidConsts.OTA_DATA
                            ) != null
                        if (otaDataCheck) {
                            val homekitCheck =
                                gatt?.getService(UuidConsts.HOMEKIT_SERVICE) != null
                            if (!homekitCheck) {
                                ota_mode = true
                                val otaDataProperty =
                                    gatt?.getService(UuidConsts.OTA_SERVICE)
                                        ?.getCharacteristic(
                                            UuidConsts.OTA_DATA
                                        )?.properties
                                if ((otaDataProperty == 12) || (otaDataProperty == 8) || (otaDataProperty == 10)) {
                                    //reliable = true;
                                } else if (ota_mode && otaDataProperty == 4) {
                                    //reliable = false;
                                }
                            }
                        }
                    }
                    gatt?.let {
                        otaUploadStatus.postValue(hashMapOf<String, Pair<Long, Int>>().apply {
                            val otaStatus=if (ota_mode) 1 else 0
                            this[it.device.address]=System.currentTimeMillis() to otaStatus
                        })
                    }
                }
            }


            override fun onCharacteristicWrite(
                gatt: BluetoothGatt?,
                characteristic: BluetoothGattCharacteristic?,
                status: Int
            ) {
                super.onCharacteristicWrite(gatt, characteristic, status)
                if (status==0){
                    if ((characteristic?.uuid == UuidConsts.OTA_CONTROL)) { //OTA Control Callback Handling
                        if (characteristic.value.size == 1) {
                            if (characteristic.value[0] == 0x00.toByte()) {
//                                        Timber.d("Callback: Control %s, status = %d",
//                                            Converters.bytesToHexWhitespaceDelimited(characteristic.value), status)
                                gatt?.let {
                                    otaControl.postValue(hashMapOf<String, Pair<Long, Int>>().apply {
                                        this[it.device.address]=System.currentTimeMillis() to 0
                                    })
                                }
                            }
                            if (characteristic.value[0] == 0x03.toByte()) {
                                gatt?.let {
                                    otaControl.postValue(hashMapOf<String, Pair<Long, Int>>().apply {
                                        this[it.device.address]=System.currentTimeMillis() to 3
                                    })
                                }
                            }
                        } else {
//                                    Timber.i("OTA_Control: received: %s",
//                                        Converters.bytesToHexWhitespaceDelimited(characteristic.value)
//                                    )
                            if (characteristic.value[0] == 0x00.toByte() && characteristic.value[1] == 0x02.toByte()) {
//                                        Timber.i("HomeKit: reading OTA_Control...")
                                gatt?.readCharacteristic(characteristic)
                            }
                        }
                    }
                    if ((characteristic?.uuid == UuidConsts.OTA_DATA)) {   //OTA Data Callback Handling
                        //todo
                        gatt?.let {
                            otaControl.postValue(hashMapOf<String, Pair<Long, Int>>().apply {
                                this[it.device.address]=System.currentTimeMillis() to 4
                            })
                        }
                    }
                }
            }

        })

    }

    /**
     *  TP960通知
     */
    fun notifyTP960Device(bleDevice: BleDevice) {
        var hasService = false
        var hasNotify = false
        BleManager.getInstance().getBluetoothGattServices(bleDevice).forEach { it ->
            Log.d(
                "123->",
                "serviceUUID=${it.uuid}"
            )
            if (it.uuid.toString() == BLUETOOTH_SERVICE_UUID_960) {
                hasService = true
            }
            it.characteristics.forEach { item ->
                Log.d(
                    "123->",
                    "characteristicsUUID=${item.uuid}"
                )
                if (item.uuid.toString() == BLUETOOTH_NOTIFY_UUID_960) {
                    hasNotify = true
                }
            }
        }
        if (!hasService && !hasNotify) {
            BleManager.getInstance().disconnect(bleDevice)
            return
        }
        BleManager.getInstance().notify(bleDevice, BLUETOOTH_SERVICE_UUID_960,
            BLUETOOTH_NOTIFY_UUID_960, object : BleNotifyCallback() {
                override fun onNotifySuccess() {
                    Log.d(
                        "123->",
                        "onNotifySuccess  TP960"
                    )
                    connectSuccess.value = linkedMapOf<String, Long>().apply {
                        this[bleDevice.mac] = System.currentTimeMillis()
                    }
                    getHistoryTP960Temp(bleDevice.mac, 0)
                }

                override fun onNotifyFailure(exception: BleException?) {

                }

                override fun onCharacteristicChanged(data: ByteArray?) {
                    val msg = HexUtil.formatHexString(data)
                    Log.d(
                        "123->",
                        "onNotifySuccess  TP960 length=${msg.length}  msg=$msg " +
                                " receiveSize=$receiveSize  totalLength=$totalLength  "
                    )
                    val msgLength = msg.length
                    val dataList = mutableListOf<ProbeBean>()
                    when {
                        (msg.startsWith("10", true) && receiveSize == 0) ||
                                (msg.startsWith("1000", true) && msg.length == 12) -> {
                            //10003a00960b
                            if (msg.length <= 12) {
                                val data1 = ProbeBean(address = bleDevice.mac)
                                dataList.add(data1.formatProbe1By960(msg))
                            } else {
                                val data1 = ProbeBean(address = bleDevice.mac)
                                val data2 = ProbeBean(address = bleDevice.mac)

                                dataList.add(data1.formatProbe1By960(msg))
                                dataList.add(data2.formatProbe2By960(msg))

                            }
                            cacheMsgData.remove(bleDevice.mac)
                            cacheMsgData[bleDevice.mac] = dataList
                            workingMap[bleDevice.mac] = true
//                            cacheMsgDataTP960.clear()
//                            cacheMsgDataTP960.addAll(dataList)
//                            notifyMsgDataCacheTP960.clear()
//                            notifyMsgDataCacheTP960.addAll(dataList)
                            notifyMsgData.value = hashMapOf<Long, MutableList<ProbeBean>>().apply {
                                this[System.currentTimeMillis()] =
                                    mutableListOf<ProbeBean>().apply {
                                        this.addAll(dataList)
                                    }
                            }
                            notifyRefreshTempData.value = dataList
                        }
                        msg.startsWith("02", true) && totalLength == 0 -> {
                            //0212f90300013800f9f80300   0283f9030003380038003800f9f8030038f9030077f90300
                            val tempSize = msg.substring(10, 12).toInt(16)
                            totalLength = 12 + tempSize * 12
                            receiveSize = msgLength
                            sbStringTP960.delete(0, sbStringTP960.length)
                            sbStringTP960.append(msg)
                            if (receiveSize == totalLength) {
                                totalLength = 0
                                val tempList = mutableListOf<TempBean>()
                                val tempStr = msg.substring(12, 12 + 4 * tempSize)
                                for (i in tempStr.indices) {
                                    if (i % 4 == 0) {
                                        val str1 = tempStr.substring(i, i + 4)
                                        val tempBean = TempBean()
                                        tempBean.address = bleDevice.mac
                                        tempBean.tempNum1 = (Integer.parseInt(
                                            str1.substring(2, 4) + str1.substring(0, 2), 16
                                        ) - 30).toString()
                                        tempList.add(tempBean)
                                    }
                                }
                                val currentTime = System.currentTimeMillis()
                                for (i in tempList.size - 1 downTo 0) {
                                    tempList[i].tempTime =
                                        (currentTime - (tempList.size - i) * 60 * 1000).toString()
                                }
                                if (!tempListCache.containsKey(bleDevice.mac)) {
                                    tempListCache[bleDevice.mac] = mutableListOf()
                                }
                                tempListCache[bleDevice.mac]?.clear()
                                tempListCache[bleDevice.mac]?.addAll(tempList)
                                notifyHistoryTempTP960Data.value =
                                    hashMapOf<Int, MutableList<TempBean>>().apply {
                                        this[0] = tempList
                                    }
                                receiveSize = 0
                                totalLength = 0
                                sbStringTP960.delete(0, sbStringTP960.length)
                            }
                        }
                        msg.startsWith("12", true) && totalLength == 0 -> {
                            val probeIndex = Integer.parseInt(msg.substring(2, 4), 16)
                            val status = Integer.parseInt(msg.substring(4, 6), 16)
                            notifyTP960ProbeStatusForever.value =
                                hashMapOf<String, Pair<Int, Int>>().apply {
                                    this[bleDevice.mac] = probeIndex to status
                                }
                            println("123-> ProbeStatus  probeIndex=$probeIndex  status=$status")
                        }
                        (msg.startsWith("11", true) ||
                                msg.startsWith("05", true))
                                && totalLength == 0 && msg.length < 5 -> {
                            val status = Integer.parseInt(msg.substring(2, 4), 16)
                            notifyTP960BoxBattery.value = hashMapOf<String, Int>().apply {
                                this[bleDevice.mac] = status
                            }
                        }
                        msg.startsWith("13", true) && totalLength == 0 -> {
                            val probeIndex = Integer.parseInt(msg.substring(2, 4), 16)
                            notifyTP960AlarmClose.value =
                                hashMapOf<String, Pair<Long, Int>>().apply {
                                    this[bleDevice.mac] = System.currentTimeMillis() to probeIndex
                                }
                        }
                        msg.startsWith("01", true) && totalLength == 0 && msg.length < 11 -> {
                            //目前固定只有一个探针
                            val probeIndex = 0
                            val status = Integer.parseInt(
                                msg.substring(8, 10) +
                                        msg.substring(6, 8), 16
                            ).toFloat() / 1000
                            println("123-> ProbeBattery=$status  msg=$msg")
                            notifyTP960ProbeBattery.value =
                                hashMapOf<String, Pair<Int, Float>>().apply {
                                    this[bleDevice.mac] = probeIndex to status
                                }
                        }
                        (msg.startsWith("03", true) && totalLength == 0) ||
                                msg == "03" -> {


                        }
                        (msg.startsWith("04", true) && totalLength == 0) ||
                                msg == "04" -> {


                        }
                        ((msg.startsWith("81", true) ||
                                msg.startsWith("82", true) ||
                                msg.startsWith("83", true) ||
                                msg.startsWith("84", true)) && totalLength == 0) ||
                                msg == "81" || msg == "82" || msg == "83" || msg == "84" -> {


                        }
                        else -> {
                            if (receiveSize < totalLength) {
                                receiveSize += msgLength
                                sbStringTP960.append(msg)
                                if (receiveSize == totalLength) {
                                    val total = totalLength;
                                    totalLength = 0
                                    val tempList = mutableListOf<TempBean>()
                                    val tempStr = sbStringTP960.toString()
                                        .substring(12, 12 + 4 * (total - 12) / 12)
                                    for (i in tempStr.indices) {
                                        if (i % 4 == 0) {
                                            val str1 = tempStr.substring(i, i + 4)
                                            val tempBean = TempBean()
                                            tempBean.address = bleDevice.mac
                                            tempBean.tempNum1 = (Integer.parseInt(
                                                str1.substring(2, 4) + str1.substring(0, 2), 16
                                            ) - 30).toString()
                                            tempList.add(tempBean)
                                        }
                                    }
                                    val currentTime = System.currentTimeMillis()
                                    for (i in tempList.size - 1 downTo 0) {
                                        tempList[i].tempTime =
                                            (currentTime - (tempList.size - i) * 60 * 1000).toString()
                                    }
                                    if (!tempListCache.containsKey(bleDevice.mac)) {
                                        tempListCache[bleDevice.mac] = mutableListOf()
                                    }
                                    tempListCache[bleDevice.mac]?.clear()
                                    tempListCache[bleDevice.mac]?.addAll(tempList)
                                    notifyHistoryTempTP960Data.value =
                                        hashMapOf<Int, MutableList<TempBean>>().apply {
                                            this[0] = tempList
                                        }
                                    receiveSize = 0
                                    totalLength = 0
                                    sbStringTP960.delete(0, sbStringTP960.length)
                                }
                            } else {
                                receiveSize = 0
                                totalLength = 0
                            }
                        }
                    }
                }
            })
    }


    /**
     * 合并设备存储历史记录和app本地存储历史记录
     */
    fun addDeviceHistoryDataToLocal(
        address: String,
        probeIndex: Int,
        tempList: MutableList<TempBean>
    ) {
        if (LocalDataDao.INSTANCE.cacheProbeHistory.containsKey("${address}_${probeIndex}")) {
            val needAddMap = hashMapOf<Int, ProbeHistoryBean>()
            LocalDataDao.INSTANCE.cacheProbeHistory["${address}_${probeIndex}"]?.let {
                for (i in 0 until it.size) {
                    if (i < it.size - 1) {
                        val item = it[i]
                        val nextItem = it[i + 1]
                        val intervalTime =
                            (nextItem.tempTime.toLong() - item.tempTime.toLong()) / 60000
                        if (intervalTime > 1) {
                            val intervalList = mutableListOf<TempBean>()
                            for (t in 0 until tempList.size) {
                                if (tempList[t].tempTime.toLong() > item.tempTime.toLong() &&
                                    tempList[t].tempTime.toLong() < nextItem.tempTime.toLong()
                                ) {
                                    intervalList.add(tempList[i])
                                }
                            }
                            for (j in 0 until intervalList.size) {
                                val tempNUm = when (probeIndex) {
                                    0 -> intervalList[j].tempNum1
                                    1 -> intervalList[j].tempNum2
                                    2 -> intervalList[j].tempNum3
                                    3 -> intervalList[j].tempNum4
                                    else -> intervalList[j].tempNum1
                                }
                                val historyBean = ProbeHistoryBean(
                                    probeIndex,
                                    intervalList[j].address, tempNUm,
                                    intervalList[j].tempTime, item.profile
                                )
                                needAddMap[i + j + 1] = historyBean
                            }
                        }
                    }
                }
                needAddMap.keys.forEach { keyIndex ->
                    needAddMap[keyIndex]?.let { mapItem ->
                        it.add(keyIndex, mapItem)
                    }
                }
            }
        }
    }

    var tempDataSize = 0
    val tempTP359HistoryList = mutableListOf<TempHumBean>()

    /**
     * TP359通知
     */
    fun notifyTP359Device(bleDevice: BleDevice) {
        var hasService = false
        var hasNotify = false
        BleManager.getInstance().getBluetoothGattServices(bleDevice).forEach { it ->
            Log.d(
                "123->",
                "serviceUUID=${it.uuid}"
            )
            if (it.uuid.toString() == BLUETOOTH_SERVICE_UUID_359) {
                hasService = true
            }
            it.characteristics.forEach { item ->
                Log.d(
                    "123->",
                    "characteristicsUUID=${item.uuid}"
                )
                if (item.uuid.toString() == BLUETOOTH_NOTIFY_UUID_359) {
                    hasNotify = true
                }
            }
        }
        if (!hasService && !hasNotify) {
            BleManager.getInstance().disconnect(bleDevice)
            return
        }
        BleManager.getInstance().notify(bleDevice, BLUETOOTH_SERVICE_UUID_359,
            BLUETOOTH_NOTIFY_UUID_359, object : BleNotifyCallback() {
                override fun onNotifySuccess() {
                    Log.d(
                        "123->",
                        "onNotifySuccess  TP359"
                    )
                    connectSuccess.value = linkedMapOf<String, Long>().apply {
                        this[bleDevice.mac] = System.currentTimeMillis()
                    }
                }

                override fun onNotifyFailure(exception: BleException?) {

                }

                override fun onCharacteristicChanged(data: ByteArray?) {
                    val msg = HexUtil.formatHexString(data)
                    Log.d(
                        "123->",
                        "onNotifySuccess  TP359 length=${msg.length}  tempDataSize=$tempDataSize  msg=$msg"
                    )
                    val dataList = mutableListOf<ProbeBean>()
                    when {
                        msg.startsWith("C2", true) &&
                                msg.endsWith("2C", true) -> {
                            val data1 = ProbeBean(address = bleDevice.mac)
                            dataList.add(data1.formatProbe1By359(msg))

                            notifyMsgData.value = hashMapOf<Long, MutableList<ProbeBean>>().apply {
                                this[System.currentTimeMillis()] =
                                    mutableListOf<ProbeBean>().apply {
                                        this.addAll(dataList)
                                    }
                            }
                            notifyRefreshTempData.value = dataList
                            notifyMsgDataCache.remove(bleDevice.mac)
                            notifyMsgDataCache[bleDevice.mac] = dataList
                        }
                        msg.startsWith("A7", true) &&
                                msg.endsWith("7A", true) -> {
                            if (tempDataSize == 0) {
                                tempTP359HistoryList.clear()
                            }
                            //每条数据间隔75秒   24x60x60/288/4=75
                            tempDataSize += 1
                            if (tempDataSize == 288) {
                                tempDataSize = 0
                                val currentTime = System.currentTimeMillis()
                                val m = currentTime % (60 * 1000)
                                for (i in 0 until tempTP359HistoryList.size) {
                                    tempTP359HistoryList[i].tempTime =
                                        (currentTime - m - (tempTP359HistoryList.size - i - 1) * 60 * 1000).toString()
                                    println("======>   i=$i   tempTime=${tempTP359HistoryList[i].tempTime}  tempNum=${tempTP359HistoryList[i].tempNum}")
                                }
                                tempTP359HistoryList.sortBy { it.tempTime.toLong() }
                                notifyHistoryTempTP359Data.value =
                                    hashMapOf<Int, MutableList<TempHumBean>>().apply {
                                        this[1] = tempTP359HistoryList
                                    }
                            } else {
                                //a70100000901440a01440901440a01440a01447a
                                val tempBean = TempHumBean(address = bleDevice.mac)
                                tempBean.tempNum =
                                    ((msg.substring(10, 12) + msg.substring(8, 10)).toLong(16)
                                        .toFloat() / 10).toString()
                                tempBean.humidityNum = msg.substring(12, 14).toLong(16).toString()

                                val tempBean1 = TempHumBean(address = bleDevice.mac)
                                tempBean1.tempNum =
                                    ((msg.substring(16, 18) + msg.substring(14, 16)).toLong(16)
                                        .toFloat() / 10).toString()
                                tempBean1.humidityNum = msg.substring(18, 20).toLong(16).toString()

                                val tempBean2 = TempHumBean(address = bleDevice.mac)
                                tempBean2.tempNum =
                                    ((msg.substring(22, 24) + msg.substring(20, 22)).toLong(16)
                                        .toFloat() / 10).toString()
                                tempBean2.humidityNum = msg.substring(24, 26).toLong(16).toString()

                                val tempBean3 = TempHumBean(address = bleDevice.mac)
                                tempBean3.tempNum =
                                    ((msg.substring(28, 30) + msg.substring(26, 28)).toLong(16)
                                        .toFloat() / 10).toString()
                                tempBean3.humidityNum = msg.substring(30, 32).toLong(16).toString()

                                tempTP359HistoryList.add(tempBean)
                                tempTP359HistoryList.add(tempBean1)
                                tempTP359HistoryList.add(tempBean2)
                                tempTP359HistoryList.add(tempBean3)
                            }
                        }
                        msg.startsWith("A6", true) &&
                                msg.endsWith("6A", true) -> {
                            if (tempDataSize == 0) {
                                tempTP359HistoryList.clear()
                            }
                            //每条数据间隔1小时   7x24x60x60/34/4=
                            tempDataSize += 1
                            if (tempDataSize == 34) {
                                tempDataSize = 0
                                val currentTime = System.currentTimeMillis()
                                val h = currentTime % (60 * 60 * 1000)
                                for (i in 0 until tempTP359HistoryList.size) {
                                    tempTP359HistoryList[i].tempTime =
                                        (currentTime - h - (tempTP359HistoryList.size - i - 1) *
                                                (7 * 24 * 60 * 60 / 34 / 4 * 1000).toLong()).toString()
                                }
                                tempTP359HistoryList.sortBy { it.tempTime.toLong() }
//                                val date = Date()
//                                val item =
//                                    tempTP359HistoryList.first {
//                                        date.time = it.tempTime.toLong()
//                                        val timeStr = dateFormat.format(date)
//                                        timeStr.split(" ")[1] == "00:00"
//                                    }
//                                val index = tempTP359HistoryList.indexOf(item)
//                                val newList = tempTP359HistoryList.subList(
//                                    index,
//                                    tempTP359HistoryList.size
//                                )
//                                val lastItem = newList.last()
//                                val a = newList.size % 24
//                                for (i in 0 until a) {
//                                    val tempBean = TempHumBean(address = bleDevice.mac)
//                                    tempBean.tempTime =
//                                        (lastItem.tempTime.toLong() + 60 * 60 * 1000).toString()
//                                    tempBean.tempNum = "25.3"
//                                    tempBean.humidityNum = "58"
//                                    newList.add(tempBean)
//                                }
                                notifyHistoryTempTP359Data.value =
                                    hashMapOf<Int, MutableList<TempHumBean>>().apply {
                                        this[2] = tempTP359HistoryList
                                    }
                            } else {
                                //a70100000901440a01440901440a01440a01447a
                                val tempBean = TempHumBean(address = bleDevice.mac)
                                if (msg.substring(10, 12) + msg.substring(8, 10) == "ffff") {
                                    tempBean.tempNum = "23"
                                } else {
                                    tempBean.tempNum =
                                        ((msg.substring(10, 12) + msg.substring(8, 10)).toLong(16)
                                            .toFloat() / 10).toString()
                                }
                                if (msg.substring(12, 14) == "ff") {
                                    tempBean.humidityNum = "60"
                                } else {
                                    tempBean.humidityNum =
                                        msg.substring(12, 14).toLong(16).toString()
                                }

                                val tempBean1 = TempHumBean(address = bleDevice.mac)
                                if (msg.substring(16, 18) + msg.substring(14, 16) == "ffff") {
                                    tempBean1.tempNum = "23"
                                } else {
                                    tempBean1.tempNum =
                                        ((msg.substring(16, 18) + msg.substring(14, 16)).toLong(16)
                                            .toFloat() / 10).toString()
                                }
                                if (msg.substring(18, 20) == "ff") {
                                    tempBean1.humidityNum = "60"
                                } else {
                                    tempBean1.humidityNum =
                                        msg.substring(18, 20).toLong(16).toString()
                                }

                                val tempBean2 = TempHumBean(address = bleDevice.mac)
                                if (msg.substring(22, 24) + msg.substring(20, 22) == "ffff") {
                                    tempBean2.tempNum = "23"
                                } else {
                                    tempBean2.tempNum =
                                        ((msg.substring(22, 24) + msg.substring(20, 22)).toLong(16)
                                            .toFloat() / 10).toString()
                                }
                                if (msg.substring(24, 26) == "ff") {
                                    tempBean2.humidityNum = "60"
                                } else {
                                    tempBean2.humidityNum =
                                        msg.substring(24, 26).toLong(16).toString()
                                }

                                val tempBean3 = TempHumBean(address = bleDevice.mac)
                                if (msg.substring(28, 30) + msg.substring(26, 28) == "ffff") {
                                    tempBean3.tempNum = "23"
                                } else {
                                    tempBean3.tempNum =
                                        ((msg.substring(28, 30) + msg.substring(26, 28)).toLong(16)
                                            .toFloat() / 10).toString()
                                }
                                if (msg.substring(30, 32) == "ff") {
                                    tempBean3.humidityNum = "60"
                                } else {
                                    tempBean3.humidityNum =
                                        msg.substring(30, 32).toLong(16).toString()
                                }

                                tempTP359HistoryList.add(tempBean)
                                tempTP359HistoryList.add(tempBean1)
                                tempTP359HistoryList.add(tempBean2)
                                tempTP359HistoryList.add(tempBean3)
                            }
                        }
                        msg.startsWith("A8", true) &&
                                msg.endsWith("8A", true) -> {
                            if (tempDataSize == 0) {
                                tempTP359HistoryList.clear()
                            }
                            //每条数据间隔75秒   7x24x60x60/34/4=
                            tempDataSize += 1
                            if (tempDataSize == 1752) {
                                tempDataSize = 0
                                val currentTime = System.currentTimeMillis()
                                val h = currentTime % (60 * 60 * 1000)
                                for (i in 0 until tempTP359HistoryList.size) {
                                    tempTP359HistoryList[i].tempTime =
                                        (currentTime - h - (tempTP359HistoryList.size - i - 1) * 60 * 60 * 1000).toString()
                                }
                                tempTP359HistoryList.sortBy { it.tempTime.toLong() }
                                notifyHistoryTempTP359Data.value =
                                    hashMapOf<Int, MutableList<TempHumBean>>().apply {
                                        this[3] = tempTP359HistoryList
                                    }
                            } else {
                                //a70100000901440a01440901440a01440a01447a
                                val tempBean = TempHumBean(address = bleDevice.mac)
                                if (msg.substring(10, 12) + msg.substring(8, 10) == "ffff") {
                                    tempBean.tempNum = "23"
                                } else {
                                    tempBean.tempNum =
                                        ((msg.substring(10, 12) + msg.substring(8, 10)).toLong(16)
                                            .toFloat() / 10).toString()
                                }
                                if (msg.substring(12, 14) == "ff") {
                                    tempBean.humidityNum = "60"
                                } else {
                                    tempBean.humidityNum =
                                        msg.substring(12, 14).toLong(16).toString()
                                }

                                val tempBean1 = TempHumBean(address = bleDevice.mac)
                                if (msg.substring(16, 18) + msg.substring(14, 16) == "ffff") {
                                    tempBean1.tempNum = "23"
                                } else {
                                    tempBean1.tempNum =
                                        ((msg.substring(16, 18) + msg.substring(14, 16)).toLong(16)
                                            .toFloat() / 10).toString()
                                }
                                if (msg.substring(18, 20) == "ff") {
                                    tempBean1.humidityNum = "60"
                                } else {
                                    tempBean1.humidityNum =
                                        msg.substring(18, 20).toLong(16).toString()
                                }

                                val tempBean2 = TempHumBean(address = bleDevice.mac)
                                if (msg.substring(22, 24) + msg.substring(20, 22) == "ffff") {
                                    tempBean2.tempNum = "23"
                                } else {
                                    tempBean2.tempNum =
                                        ((msg.substring(22, 24) + msg.substring(20, 22)).toLong(16)
                                            .toFloat() / 10).toString()
                                }
                                if (msg.substring(24, 26) == "ff") {
                                    tempBean2.humidityNum = "60"
                                } else {
                                    tempBean2.humidityNum =
                                        msg.substring(24, 26).toLong(16).toString()
                                }

                                val tempBean3 = TempHumBean(address = bleDevice.mac)
                                if (msg.substring(28, 30) + msg.substring(26, 28) == "ffff") {
                                    tempBean3.tempNum = "23"
                                } else {
                                    tempBean3.tempNum =
                                        ((msg.substring(28, 30) + msg.substring(26, 28)).toLong(16)
                                            .toFloat() / 10).toString()
                                }
                                if (msg.substring(30, 32) == "ff") {
                                    tempBean3.humidityNum = "60"
                                } else {
                                    tempBean3.humidityNum =
                                        msg.substring(30, 32).toLong(16).toString()
                                }
                                tempTP359HistoryList.add(tempBean)
                                tempTP359HistoryList.add(tempBean1)
                                tempTP359HistoryList.add(tempBean2)
                                tempTP359HistoryList.add(tempBean3)
                            }
                        }
                    }
                }

            })
    }

    /**
     * BBQ 通知
     */
    fun notifyBBQDevice(bleDevice: BleDevice) {
        var hasService = false
        var hasNotify = false
        BleManager.getInstance().getBluetoothGattServices(bleDevice).forEach { it ->
            Log.d(
                "123->",
                "serviceUUID=${it.uuid}"
            )
            if (it.uuid.toString() == BLUETOOTH_SERVICE_UUID) {
                hasService = true

            }
            it.characteristics.forEach { item ->
                Log.d(
                    "123->",
                    "characteristicsUUID=${item.uuid}"
                )
                if (item.uuid.toString() == BLUETOOTH_NOTIFY_UUID) {
                    hasNotify = true
                }
            }
        }
        if (!hasService && !hasNotify) {
            BleManager.getInstance().disconnect(bleDevice)
            return
        }
        BleManager.getInstance().notify(bleDevice, BLUETOOTH_SERVICE_UUID,
            BLUETOOTH_NOTIFY_UUID, object : BleNotifyCallback() {
                override fun onNotifySuccess() {
                    Log.d(
                        "123->",
                        "onNotifySuccess"
                    )
                    getDeviceInfo(bleDevice)
                    connectSuccess.value = linkedMapOf<String, Long>().apply {
                        this[bleDevice.mac] = System.currentTimeMillis()
                    }
                }

                override fun onNotifyFailure(exception: BleException?) {

                }

                override fun onCharacteristicChanged(data: ByteArray?) {
                    data?.let {
                        val msg = HexUtil.formatHexString(data)
                        Log.d(
                            "123->",
                            "onNotifySuccess  msg=$msg"
                        )
                        //aadd0019001b0019001a06004aff
                        //aadd0019ff9c001aff9c05004bff
                        //aadd001a0019070017ff
                        val dataList = mutableListOf<ProbeBean>()
                        when {
                            msg.startsWith("aadd", true) -> {
                                if (msg.length <= 20) {
                                    val data1 = ProbeBean(address = bleDevice.mac)
                                    val data2 = ProbeBean(address = bleDevice.mac)

                                    dataList.add(data1.formatProbe1ByGrill(msg))
                                    dataList.add(data2.formatProbe2ByGrill(msg))
                                } else {
                                    val data1 = ProbeBean(address = bleDevice.mac)
                                    val data2 = ProbeBean(address = bleDevice.mac)
                                    val data3 = ProbeBean(address = bleDevice.mac)
                                    val data4 = ProbeBean(address = bleDevice.mac)

                                    dataList.add(data1.formatProbe1ByBBQ(msg))
                                    dataList.add(data2.formatProbe2ByBBQ(msg))
                                    dataList.add(data3.formatProbe3ByBBQ(msg))
                                    dataList.add(data4.formatProbe4ByBBQ(msg))


                                    val tempBean = TempBean()
                                    tempBean.tempTime = System.currentTimeMillis().toString()
                                    tempBean.tempNum1 = data1.temperatureNUm
                                    tempBean.tempNum2 = data2.temperatureNUm
                                    tempBean.tempNum3 = data3.temperatureNUm
                                    tempBean.tempNum4 = data4.temperatureNUm
                                    if (!tempListCache.containsKey(bleDevice.mac)) {
                                        tempListCache[bleDevice.mac] = mutableListOf()
                                    }
                                    tempListCache[bleDevice.mac]?.add(tempBean)
                                }
                                cacheMsgData.remove(bleDevice.mac)
                                cacheMsgData[bleDevice.mac] = dataList
                                //获取到温度就开始累计更新温度数据
                                workingMap[bleDevice.mac] = true

                                notifyMsgDataCache.remove(bleDevice.mac)
                                notifyMsgDataCache[bleDevice.mac] = dataList
                                notifyMsgData.value =
                                    hashMapOf<Long, MutableList<ProbeBean>>().apply {
                                        this[System.currentTimeMillis()] =
                                            mutableListOf<ProbeBean>().apply {
                                                this.addAll(dataList)
                                            }
                                    }
                                notifyRefreshTempData.value = dataList
                            }
                            msg.startsWith("aabb", true) -> {
                                //aabb0fff0fff0fff0fff0fff0fff0fff0fff0000312e312e30051eff
                                val deviceInfoBean = DeviceInfoBean().formatInfo(msg)
                                deviceInfoBean.address = bleDevice.mac
                                notifyInfoDataCache.clear()
                                notifyInfoDataCache.add(bleDevice.mac to deviceInfoBean)
                                notifyInfoData.postValue(deviceInfoBean)
                                Log.d(
                                    "123->",
                                    "onNotifySuccess  deviceInfoBean=$deviceInfoBean"
                                )
                            }
                            msg.startsWith("aaf0", true) -> {
                                // AA F0 00 1B FF 9C FF 9C FF 9C 00 1B FF 9C FF 9C FF 9C
                                // 00 1B FF 9C FF 9C FF 9C 00 1A FF 9C FF 9C FF 9C
                                // 00 1A FF 9C FF 9C FF 9C 00 19 FF 9C FF 9C FF 9C
                                // 00 19 FF 9C FF 9C FF 9C 00 19 FF 9C FF 9C FF 9C
                                // 00 19 FF 9C FF 9C FF 9C 00 19 FF 9C FF 9C FF 9C
                                // 00 19 FF 9C FF 9C FF 9C 06 FF
                                val tempList = mutableListOf<TempBean>()
                                val tempStr = msg.substring(4, msg.length - 4)
                                if (tempStr.length % 16 == 0) {
                                    for (i in tempStr.indices) {
                                        if (i % 16 == 0) {
                                            val str1 = tempStr.substring(i, i + 16)
                                            val tempBean = TempBean()
                                            tempBean.tempNum1 =
                                                if (str1.substring(0, 4) == "ff9c") ""
                                                else Integer.parseInt(str1.substring(0, 4), 16)
                                                    .toString()
                                            tempBean.tempNum2 =
                                                if (str1.substring(4, 8) == "ff9c") ""
                                                else Integer.parseInt(str1.substring(4, 8), 16)
                                                    .toString()
                                            tempBean.tempNum3 =
                                                if (str1.substring(8, 12) == "ff9c") ""
                                                else Integer.parseInt(str1.substring(8, 12), 16)
                                                    .toString()
                                            tempBean.tempNum4 =
                                                if (str1.substring(12, 16) == "ff9c") ""
                                                else Integer.parseInt(
                                                    str1.substring(12, 16),
                                                    16
                                                )
                                                    .toString()
                                            tempList.add(tempBean)
                                        }
                                    }
                                } else if (tempStr.length % 8 == 0) {
                                    for (i in tempStr.indices) {
                                        if (i % 8 == 0) {
                                            val str1 = tempStr.substring(i, i + 8)
                                            val tempBean = TempBean()
                                            tempBean.tempNum1 =
                                                if (str1.substring(0, 4) == "ff9c") ""
                                                else Integer.parseInt(str1.substring(0, 4), 16)
                                                    .toString()
                                            tempBean.tempNum2 =
                                                if (str1.substring(4, 8) == "ff9c") ""
                                                else Integer.parseInt(str1.substring(4, 8), 16)
                                                    .toString()
                                            tempList.add(tempBean)
                                        }
                                    }
                                }

                                val currentTime = System.currentTimeMillis()
                                for (i in tempList.size - 1 downTo 0) {
                                    tempList[i].tempTime =
                                        (currentTime - (tempList.size - i) * 60 * 1000).toString()
                                }
                                LocalDataDao.INSTANCE.cacheHistoryTemp.remove(bleDevice.mac)
                                LocalDataDao.INSTANCE.cacheHistoryTemp[bleDevice.mac] = tempList

                            }
                            msg.startsWith("aaee", true) -> {
                                println("====> 报警消息 ")
                            }
                            else -> {

                            }
                        }
                    }
                }
            })
    }


    /**
     * 查询设备状态(BBQ)
     */
    fun getDeviceInfo(device: BleDevice) {
        val msg = "aabb01bcff"
        val deviceList = BleManager.getInstance().allConnectedDevice
        if (deviceList.isNotEmpty()) {
            BleManager.getInstance().write(
                device,
                BLUETOOTH_SERVICE_UUID,
                BLUETOOTH_WRITE_UUID,
                HexUtil.hexStringToBytes(msg),
                object : BleWriteCallback() {
                    override fun onWriteSuccess(
                        current: Int,
                        total: Int,
                        justWrite: ByteArray
                    ) {
                        // 发送数据到设备成功
                        logD(" 蓝牙发送数据成功 查询设备状态")

                    }

                    override fun onWriteFailure(exception: BleException) {
                        logD(" 蓝牙发送数据失败  $msg  ${exception.toString()}")
                        // 发送数据到设备失败

                    }
                })
        }
    }

    /**
     * 发送停止报警
     */
    fun sendStopAlarmMsg(deviceAddress: String, probeIndex: Int) {
        val deviceList = BleManager.getInstance().allConnectedDevice
        val mDevice = LocalDataDao.INSTANCE.getDeviceList().first { it.address == deviceAddress }
        var serviceUUID = ""
        var writeUUID = ""
        val msg = when {
            mDevice.name?.contains("bbq", true) == true -> {
                serviceUUID = BLUETOOTH_SERVICE_UUID
                writeUUID = BLUETOOTH_WRITE_UUID
                "aaee00eeff"
            }
            mDevice.name?.contains("grill", true) == true -> {
                serviceUUID = BLUETOOTH_SERVICE_UUID
                writeUUID = BLUETOOTH_WRITE_UUID
                "aaee00eeff"
            }
            mDevice.name?.contains("tp359", true) == true -> {
                ""
            }
            mDevice.name?.contains("tp960", true) == true -> {
                serviceUUID = BLUETOOTH_SERVICE_UUID_960
                writeUUID = BLUETOOTH_WRITE_UUID_960
                val profile = when (probeIndex) {
                    1 -> {
                        LocalDataDao.INSTANCE.getProfile1(deviceAddress)
                    }
                    2 -> {
                        LocalDataDao.INSTANCE.getProfile2(deviceAddress)
                    }
                    3 -> {
                        LocalDataDao.INSTANCE.getProfile3(deviceAddress)
                    }
                    4 -> {
                        LocalDataDao.INSTANCE.getProfile4(deviceAddress)
                    }
                    else -> {
                        ProfileBean(
                            "MEAT",
                            "", mutableListOf(), singleTemp = false
                        )
                    }
                }
                val num = profile.highTemperatureNum.replace("°C", "")
                    .toInt() + 30
                var numStr = Integer.toHexString(num)
                numStr = when (numStr.length) {
                    1 -> "0${numStr}00"
                    2 -> "${numStr}00"
                    3 -> "0${numStr.substring(2, 3)}${numStr.substring(0, 2)}"
                    4 -> "${numStr.substring(2, 4)}${numStr.substring(0, 2)}"
                    else -> numStr
                }
                "040${probeIndex - 1}00$numStr"
            }
            else -> {
                serviceUUID = BLUETOOTH_SERVICE_UUID
                writeUUID = BLUETOOTH_WRITE_UUID
                "aaee00eeff"
            }
        }
        if (msg.isEmpty()) {
            return
        }
        println("======> sendStopAlarmMsg msg=$msg")
        try {
            if (deviceList.isNotEmpty()) {
                BleManager.getInstance().write(
                    deviceList.first { it.mac == deviceAddress },
                    serviceUUID,
                    writeUUID,
                    HexUtil.hexStringToBytes(msg),
                    object : BleWriteCallback() {
                        override fun onWriteSuccess(
                            current: Int,
                            total: Int,
                            justWrite: ByteArray
                        ) {
                            // 发送数据到设备成功
                            logD(" 蓝牙发送数据成功  停止报警")

                        }

                        override fun onWriteFailure(exception: BleException) {
                            logD(" 蓝牙发送数据失败  ${exception.toString()}")
                            // 发送数据到设备失败

                        }
                    })
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 获取电量(TP960)
     */
    fun getBoxProbeBattery(address: String) {
        val msg = "05"
        val msg1 = "0100"
        println("getBoxBattery msg====$msg")
        val deviceList = BleManager.getInstance().allConnectedDevice.filter { it.mac == address }
        if (deviceList.isNotEmpty()) {
            BleManager.getInstance().write(
                deviceList[0],
                TP960ViewModel.BLUETOOTH_SERVICE_UUID_960,
                TP960ViewModel.BLUETOOTH_WRITE_UUID_960,
                HexUtil.hexStringToBytes(msg),
                object : BleWriteCallback() {
                    override fun onWriteSuccess(
                        current: Int,
                        total: Int,
                        justWrite: ByteArray
                    ) {
                        // 发送数据到设备成功
                        logD(" 蓝牙发送数据成功 getBoxBattery  $msg")

                    }

                    override fun onWriteFailure(exception: BleException) {
                        logD(" 蓝牙发送数据失败  ${exception.toString()}")
                        // 发送数据到设备失败

                    }
                })

            BleManager.getInstance().write(
                deviceList[0],
                TP960ViewModel.BLUETOOTH_SERVICE_UUID_960,
                TP960ViewModel.BLUETOOTH_WRITE_UUID_960,
                HexUtil.hexStringToBytes(msg1),
                object : BleWriteCallback() {
                    override fun onWriteSuccess(
                        current: Int,
                        total: Int,
                        justWrite: ByteArray
                    ) {
                        // 发送数据到设备成功
                        logD(" 蓝牙发送数据成功 getBoxBattery  $msg")

                    }

                    override fun onWriteFailure(exception: BleException) {
                        logD(" 蓝牙发送数据失败  ${exception.toString()}")
                        // 发送数据到设备失败

                    }
                })
        }
    }

    fun getTempHistoryByCache(address: String, deviceName: String) {
        notifyHistoryTempTP960Data.value =
            hashMapOf<Int, MutableList<TempBean>>().apply {
                this[0] = tempListCache[address] ?: mutableListOf<TempBean>()
            }
    }

    fun getTempHistoryByCache(address: String, probeIndex: Int) {
        val keyStr = "${address}_${probeIndex}"
        if (LocalDataDao.INSTANCE.cacheProbeHistory.containsKey(keyStr) &&
            LocalDataDao.INSTANCE.cacheProbeHistory[keyStr]?.isNotEmpty() == true
        ) {
            notifyHistoryTempData.value = LocalDataDao.INSTANCE.cacheProbeHistory
        }
    }

    private val workingMap = linkedMapOf<String, Boolean>()

    private fun stopGetTemp(address: String) {
        workingMap[address] = false
    }

    private var workingHistory = false

    /**
     * 累计存储当前温度 形成历史记录
     */
    private fun startAddNewTempToHistory() {
        workingHistory = true
        println("---> startAddNewTempToHistory workingHistory====$workingHistory")
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                val cal = Calendar.getInstance()
                cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) + 1)
                cal.set(Calendar.MILLISECOND, 0)
                val delayTime = cal.timeInMillis - System.currentTimeMillis()
                delay(delayTime)
                while (workingHistory) {
                    println("--->  addTemp2History workingHistory==$workingHistory")
                    delay(1000 * 12)
                    addTemp2History()
                }
            }
        }
    }

    /**
     * 累计存储当前温度
     */
    private fun addTemp2History() {
        workingMap.keys.forEachIndexed { _, it ->
            println("---> addTemp2History workingMap$it====${workingMap[it]}")
            if (workingMap[it] == true) {
                val tempBean = TempBean()
                tempBean.tempTime = System.currentTimeMillis().toString()
                when {
                    cacheMsgData[it]?.isEmpty() == true -> {
                        tempBean.tempNum1 = ""
                        tempBean.tempNum2 = ""
                        tempBean.tempNum3 = ""
                        tempBean.tempNum4 = ""
                    }
                    cacheMsgData[it]?.size ?: 0 > 2 -> {
                        tempBean.tempNum1 =
                            (cacheMsgData[it]?.get(0)?.temperatureNUm ?: "").toString()
                        tempBean.tempNum2 =
                            (cacheMsgData[it]?.get(1)?.temperatureNUm ?: "").toString()
                        tempBean.tempNum3 =
                            (cacheMsgData[it]?.get(2)?.temperatureNUm ?: "").toString()
                        tempBean.tempNum4 =
                            (cacheMsgData[it]?.get(3)?.temperatureNUm ?: "").toString()
                    }
                    cacheMsgData[it]?.size ?: 0 == 2 -> {
                        tempBean.tempNum1 =
                            (cacheMsgData[it]?.get(0)?.temperatureNUm ?: "0").toString()
                        tempBean.tempNum2 =
                            (cacheMsgData[it]?.get(1)?.temperatureNUm ?: "0").toString()
                    }
                    cacheMsgData[it]?.size ?: 0 == 1 -> {
                        tempBean.tempNum1 =
                            (cacheMsgData[it]?.get(0)?.temperatureNUm ?: "0").toString()
                    }
                    else -> {
                        tempBean.tempNum1 = ""
                        tempBean.tempNum2 = ""
                    }
                }
                if (tempBean.tempNum1.isEmpty() && tempBean.tempNum2.isEmpty()
                    && tempBean.tempNum3.isEmpty() && tempBean.tempNum4.isEmpty()
                ) {
                    return@forEachIndexed
                }
                var currentProfile = LocalDataDao.INSTANCE.getProfile1(it)
                for (i in 0 until 4) {
                    val currentTemp = when (i) {
                        0 -> {
                            currentProfile = LocalDataDao.INSTANCE.getProfile1(it)
                            tempBean.tempNum1
                        }
                        1 -> {
                            currentProfile = LocalDataDao.INSTANCE.getProfile2(it)
                            tempBean.tempNum2
                        }
                        2 -> {
                            currentProfile = LocalDataDao.INSTANCE.getProfile3(it)
                            tempBean.tempNum3
                        }
                        3 -> {
                            currentProfile = LocalDataDao.INSTANCE.getProfile4(it)
                            tempBean.tempNum4
                        }
                        else -> tempBean.tempNum1
                    }
                    if (currentTemp.isNotEmpty()) {
                        println("123-> currentTemp=$currentTemp")
                        if (LocalDataDao.INSTANCE.cacheProbeHistory.containsKey("${it}_${i}")) {
                            val item =
                                LocalDataDao.INSTANCE.cacheProbeHistory["${it}_${i}"]!!.last()
                            val date = Date()
                            date.time = item.tempTime.toLong()
                            val timeStr = dateFormat.format(date)
                            date.time = tempBean.tempTime.toLong()
                            val newTimeStr = dateFormat.format(date)
                            if (newTimeStr == timeStr) {
                                item.tempNum = currentTemp
                                item.profile = currentProfile
                            } else {
                                LocalDataDao.INSTANCE.cacheProbeHistory["${it}_${i}"]?.add(
                                    ProbeHistoryBean(
                                        i, it, currentTemp, System.currentTimeMillis().toString(),
                                        currentProfile
                                    )
                                )
                            }
                        } else {
                            val list = mutableListOf<ProbeHistoryBean>()
                            list.add(
                                ProbeHistoryBean(
                                    i, it, currentTemp, System.currentTimeMillis().toString(),
                                    currentProfile
                                )
                            )
                            LocalDataDao.INSTANCE.cacheProbeHistory["${it}_${i}"] = list
                        }
                        notifyHistoryTempData.postValue(LocalDataDao.INSTANCE.cacheProbeHistory)
                    }
                }
            }
        }
    }


    /**
     * 预测时间 温度历史数据
     */
    private fun startComputeHistory() {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                while (workingHistory) {
                    println("--->  addTemp2ComputeHistory workingHistory==$workingHistory")
                    delay(1000)
                    addTemp2ComputeHistory()
                }
            }
        }
    }

    //每根探针历史记录
    private val cacheProbeComputeHistory =
        Collections.synchronizedMap(hashMapOf<String, MutableList<ProbeHistoryBean>>())

    //每根探针历史记录(临时存储)
    private val cacheProbeComputeHistory1 =
        Collections.synchronizedMap(hashMapOf<String, MutableList<ProbeHistoryBean>>())

    //起始点温度
    private val cacheProbeFirstTemp =
        Collections.synchronizedMap(hashMapOf<String, Int>())

    /**
     * 累计存储当前温度 用于预测到达目标温度时间
     */
    private fun addTemp2ComputeHistory() {
        if (workingMap.isEmpty()) {
            return
        }
        workingMap.keys.forEachIndexed { _, it ->
            println("---> addTemp2ComputeHistory workingMap$it====${workingMap[it]}")
            if (workingMap[it] == true) {
                val tempBean = TempBean()
                tempBean.tempTime = System.currentTimeMillis().toString()
                when {
                    cacheMsgData[it]?.isEmpty() == true -> {
                        tempBean.tempNum1 = ""
                        tempBean.tempNum2 = ""
                        tempBean.tempNum3 = ""
                        tempBean.tempNum4 = ""
                    }
                    cacheMsgData[it]?.size ?: 0 > 2 -> {
                        tempBean.tempNum1 =
                            (cacheMsgData[it]?.get(0)?.temperatureNUm ?: "").toString()
                        tempBean.tempNum2 =
                            (cacheMsgData[it]?.get(1)?.temperatureNUm ?: "").toString()
                        tempBean.tempNum3 =
                            (cacheMsgData[it]?.get(2)?.temperatureNUm ?: "").toString()
                        tempBean.tempNum4 =
                            (cacheMsgData[it]?.get(3)?.temperatureNUm ?: "").toString()
                    }
                    cacheMsgData[it]?.size ?: 0 == 2 -> {
                        tempBean.tempNum1 =
                            (cacheMsgData[it]?.get(0)?.temperatureNUm ?: "0").toString()
                        tempBean.tempNum2 =
                            (cacheMsgData[it]?.get(1)?.temperatureNUm ?: "0").toString()
                    }
                    cacheMsgData[it]?.size ?: 0 == 1 -> {
                        tempBean.tempNum1 =
                            (cacheMsgData[it]?.get(0)?.temperatureNUm ?: "0").toString()
                    }
                    else -> {
                        tempBean.tempNum1 = ""
                        tempBean.tempNum2 = ""
                    }
                }
                if (tempBean.tempNum1.isEmpty() && tempBean.tempNum2.isEmpty()
                    && tempBean.tempNum3.isEmpty() && tempBean.tempNum4.isEmpty()
                ) {
                    return@forEachIndexed
                }
                var currentProfile = LocalDataDao.INSTANCE.getProfile1(it)
                for (i in 0 until 4) {
                    //test
//                    if (i!=0){
//                        continue
//                    }
                    val currentTemp = when (i) {
                        0 -> {
                            currentProfile = LocalDataDao.INSTANCE.getProfile1(it)
                            tempBean.tempNum1
                        }
                        1 -> {
                            currentProfile = LocalDataDao.INSTANCE.getProfile2(it)
                            tempBean.tempNum2
                        }
                        2 -> {
                            currentProfile = LocalDataDao.INSTANCE.getProfile3(it)
                            tempBean.tempNum3
                        }
                        3 -> {
                            currentProfile = LocalDataDao.INSTANCE.getProfile4(it)
                            tempBean.tempNum4
                        }
                        else -> tempBean.tempNum1
                    }
                    println(
                        "123-> clearComputeData5  index=$i  currentTemp=$currentTemp  " +
                                "currentProfile.name=${currentProfile.name}  " +
                                " currentProfile.singleTemp=${currentProfile.singleTemp} "
                    )
                    if (currentTemp.isNotEmpty() && currentProfile.name != "MEAT" && currentProfile.singleTemp) {
                        if (cacheProbeComputeHistory1.containsKey("${it}_${i}")) {
                            cacheProbeComputeHistory1["${it}_${i}"]?.add(
                                ProbeHistoryBean(
                                    i, it, currentTemp, System.currentTimeMillis().toString(),
                                    currentProfile
                                )
                            )
                            if (cacheProbeComputeHistory1["${it}_${i}"]?.size == 1) {
                                println("--->  设置起始数据1  currentTemp=$currentTemp ")
                                cacheProbeFirstTemp["${it}_${i}"] = currentTemp.toInt()
                                //test
//                                cacheProbeFirstTemp["${it}_${i}"] = 21
                            }
                        } else {
                            val list = mutableListOf<ProbeHistoryBean>()
                            list.add(
                                ProbeHistoryBean(
                                    i, it, currentTemp, System.currentTimeMillis().toString(),
                                    currentProfile
                                )
                            )
                            cacheProbeComputeHistory1["${it}_${i}"] = list
                            if (cacheProbeComputeHistory1["${it}_${i}"]?.size == 1) {
                                println("--->  设置起始数据2  currentTemp=$currentTemp ")
                                cacheProbeFirstTemp["${it}_${i}"] = currentTemp.toInt()
                                //test
//                                cacheProbeFirstTemp["${it}_${i}"] = 21
                            }
                        }
                        if (cacheProbeFirstTemp.containsKey("${it}_${i}")) {
                            println("--->  起始数据已存储 cacheProbeFirstTemp=${cacheProbeFirstTemp["${it}_${i}"]} currentTemp=$currentTemp ")
                            val lastTemp = LocalDataDao.INSTANCE.transUnitCToF(currentTemp).toInt()
                            val firstTemp =
                                LocalDataDao.INSTANCE.transUnitCToF(cacheProbeFirstTemp["${it}_${i}"].toString())
                                    .toInt()
                            println(
                                "--->  判断存储数据  lastTemp=$lastTemp  firstTemp=$firstTemp   " +
                                        "currentProfile.singleTemp=${currentProfile.singleTemp}   " +
                                        "currentProfile.highTemperatureNum=${currentProfile.highTemperatureNum}"
                            )
                            if (lastTemp - firstTemp >= 10 && currentProfile.singleTemp
                                && LocalDataDao.INSTANCE.transUnitCToF(
                                    currentProfile.highTemperatureNum
                                ).toInt() > firstTemp
                            ) {
                                println("--->  开始存储数据")
                                if (cacheProbeComputeHistory.containsKey("${it}_${i}")) {
                                    cacheProbeComputeHistory["${it}_${i}"]?.add(
                                        ProbeHistoryBean(
                                            i,
                                            it,
                                            currentTemp,
                                            System.currentTimeMillis().toString(),
                                            currentProfile
                                        )
                                    )
                                } else {
                                    val list = mutableListOf<ProbeHistoryBean>()
                                    list.add(
                                        ProbeHistoryBean(
                                            i,
                                            it,
                                            currentTemp,
                                            System.currentTimeMillis().toString(),
                                            currentProfile
                                        )
                                    )
                                    cacheProbeComputeHistory["${it}_${i}"] = list
                                }
                                if (cacheProbeComputeHistory["${it}_${i}"]!!.size < 35) {
                                    if (cacheProbeComputeHistory["${it}_${i}"]!!.size % 30 == 0) {
                                        println("--->  开始计算预测时间")
                                        val endNum = currentProfile.highTemperatureNum.toDouble()
                                        if (currentTemp.toDouble() >= endNum) {
                                            println("123->  clearComputeData1  清理计算数据")
                                            clearComputeData(it, i)
                                        } else {
                                            computeNeedTime(
                                                it, i, currentProfile.highTemperatureNum.toDouble(),
                                                cacheProbeComputeHistory["${it}_${i}"]!!
                                            )
                                        }
                                    }
                                } else {
                                    var firstNum = 0
                                    cacheProbeFirstTemp["${it}_${i}"]?.let { firstIt ->
                                        firstNum = firstIt
                                        val endNum = currentProfile.highTemperatureNum.toDouble()
                                        val percent =
                                            (currentTemp.toDouble() - firstNum) / (endNum - firstNum)
                                        if (firstNum >= endNum || currentTemp.toDouble() >= endNum) {
                                            clearComputeData(it, i)
                                            println("123->  clearComputeData2  清理计算数据")
                                        } else if (percent < 0.8) {
                                            if (cacheProbeComputeHistory["${it}_${i}"]!!.size % 30 == 0) {
                                                println("--->  开始计算预测时间")
                                                computeNeedTime(
                                                    it,
                                                    i,
                                                    currentProfile.highTemperatureNum.toDouble(),
                                                    cacheProbeComputeHistory["${it}_${i}"]!!
                                                )
                                            }
                                        } else if (percent >= 0.8 && percent < 0.9) {
                                            if (cacheProbeComputeHistory["${it}_${i}"]!!.size % 10 == 0) {
                                                println("--->  开始计算预测时间")
                                                computeNeedTime(
                                                    it,
                                                    i,
                                                    currentProfile.highTemperatureNum.toDouble(),
                                                    cacheProbeComputeHistory["${it}_${i}"]!!
                                                )
                                            }
                                        } else if (percent >= 0.9 && percent < 0.95) {
                                            if (cacheProbeComputeHistory["${it}_${i}"]!!.size % 3 == 0) {
                                                println("--->  开始计算预测时间")
                                                computeNeedTime(
                                                    it,
                                                    i,
                                                    currentProfile.highTemperatureNum.toDouble(),
                                                    cacheProbeComputeHistory["${it}_${i}"]!!
                                                )
                                            }
                                        } else if (percent >= 0.95 && percent < 1) {
                                            computeNeedTime(
                                                it, i, currentProfile.highTemperatureNum.toDouble(),
                                                cacheProbeComputeHistory["${it}_${i}"]!!
                                            )
                                        } else if (percent >= 1) {
                                            clearComputeData(it, i)
                                            println("123->  clearComputeData3  清理计算数据")
                                        }
                                    }

//                                    if (cacheProbeComputeHistory["${it}_${i}"]!!.size % 30 == 0) {
//                                        println("--->  开始计算预测时间")
//                                        computeNeedTime(
//                                            it, i, currentProfile.highTemperatureNum.toDouble(),
//                                            cacheProbeComputeHistory["${it}_${i}"]!!
//                                        )
//                                    }
                                }

                                if (cacheProbeComputeHistory["${it}_${i}"]!!.size > 5 * 60) {
                                    val removeList =
                                        cacheProbeComputeHistory["${it}_${i}"]!!.subList(0, 60)
                                    cacheProbeComputeHistory["${it}_${i}"]!!.removeAll(removeList)
                                }
                            } else {
                                if (cacheProbeComputeHistory.containsKey("${it}_${i}") &&
                                    cacheProbeComputeHistory["${it}_${i}"]!!.size > 2 * 60
                                ) {
                                    println("123->  clearComputeData4  清理计算数据")
                                    val removeList =
                                        cacheProbeComputeHistory["${it}_${i}"]!!.subList(0, 60)
                                    cacheProbeComputeHistory["${it}_${i}"]!!.removeAll(removeList)
                                    probeTempComputeTime.postValue(System.currentTimeMillis() to
                                            hashMapOf<String, String>().apply {
                                                this["${it}_${i}"] = ""
                                            })
                                }
                            }
                        }
                    } else {
                        println("123->  clearComputeData5  清理计算数据")
                        clearComputeData(it, i)
                    }
                }
            } else {
                for (i in 0 until 4) {
                    println("123->  clearComputeData6  清理计算数据")
                    clearComputeData(it, i)
                }
            }
        }
    }

    /**
     * 清空数据重新计算
     */
    private fun clearComputeData(address: String, probeIndex: Int) {
        cacheProbeComputeHistory["${address}_${probeIndex}"]?.clear()
        cacheProbeComputeHistory1["${address}_${probeIndex}"]?.clear()
        cacheProbeFirstTemp.remove("${address}_${probeIndex}")
        probeTempComputeTime.postValue(System.currentTimeMillis() to
                hashMapOf<String, String>().apply {
                    this["${address}_${probeIndex}"] = ""
                })
    }


    /**
     * 预测时间
     */
    private fun computeNeedTime(
        address: String,
        probeIndex: Int,
        targetTemp: Double,
        tempListCache: MutableList<ProbeHistoryBean>
    ) {
        if (tempListCache.size >= 2) {
            val lineRegression = MyLineRegression()
            val list = tempListCache
            val xTime = list.map { it.tempTime.toDouble() }.toMutableList()
            val yTemp = list.map { it.tempNum.toDouble() }.toMutableList()

            println("====> lineRegression x[]=$xTime   y[]=$yTemp")
            val map = lineRegression.lineRegression(
                xTime.toDoubleArray(),
                yTemp.toDoubleArray()
            )
            println("====> lineRegression=$map")
            val a = map["a"]!!
            val b = map["b"]!!
            val r = map["r"]!!
            val x = (targetTemp - b) / a
            val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
            val date = Date()
//            date.time = x.toLong() + firstTime.toLong()
//            val fTime = dateFormat.format(date)
//            val sTime = (x.toLong() + firstTime.toLong() - System.currentTimeMillis()) / 1000

            date.time = x.toLong()
            val fTime = dateFormat.format(date)
            val sTime = (x.toLong() - System.currentTimeMillis()) / 1000
            println("====> 预测时间  sTime=$sTime  address=$address probeIndex=$probeIndex")
            if (sTime > 0 && sTime < 6 * 60 * 60) {
                val newH = sTime / (60 * 60)
                val newM = sTime % (60 * 60) / 60
                val newS = sTime % 60
                val newTime = "${if (newH < 10) "0$newH" else newH.toString()}:${
                    if (newM < 10) "0$newM"
                    else newM.toString()
                }:${if (newS < 10) "0$newS" else newS.toString()}"
                probeTempComputeTime.postValue(System.currentTimeMillis() to
                        hashMapOf<String, String>().apply {
                            newTime.also { this["${address}_${probeIndex}"] = it }
                        })
            } else {
                probeTempComputeTime.postValue(System.currentTimeMillis() to
                        hashMapOf<String, String>().apply {
                            this["${address}_${probeIndex}"] = ""
                        })
            }
            println("====> 预测时间=$x   $fTime  address=$address probeIndex=$probeIndex")
        } else {
            probeTempComputeTime.postValue(System.currentTimeMillis() to
                    hashMapOf<String, String>().apply {
                        this["${address}_${probeIndex}"] = ""
                    })
            println("====> 预测时间 cacheHistoryTemp is empty  address=$address probeIndex=$probeIndex")
        }
    }

    override fun onCleared() {
        BleManager.getInstance().disconnectAllDevice()
        BleManager.getInstance().destroy()
        workingHistory = false
        LocalDataDao.INSTANCE.stopSaveHistory()
        super.onCleared()
    }

    fun removeDevice(item: DeviceBean) {
        val deviceList = BleManager.getInstance().allConnectedDevice.filter {
            it.mac == item.address
        }
        if (deviceList.isNotEmpty()) {
            stopGetTemp(deviceList.first().mac)
            BleManager.getInstance().disconnect(deviceList.first())
            cacheMsgData.remove(deviceList.first().mac)
        }
        LocalDataDao.INSTANCE.clearSettingsByAddress(item.address)
    }

    fun removeDevice(address: String) {
        val deviceList = BleManager.getInstance().allConnectedDevice.filter {
            it.mac == address
        }
        if (deviceList.isNotEmpty()) {
            stopGetTemp(deviceList.first().mac)
            BleManager.getInstance().disconnect(deviceList.first())
            cacheMsgData.remove(deviceList.first().mac)
        }
        LocalDataDao.INSTANCE.clearSettingsByAddress(address)
    }

    fun resetProfile(itList: MutableList<ProbeBean>) {
        val deviceType = LocalDataDao.INSTANCE.getDeviceList().first {
            it.address == itList.last().address
        }.deviceType
        for (i in 0 until itList.size) {
            val profile = when (i) {
                0 -> {
                    LocalDataDao.INSTANCE.getProfile1(itList[i].address)
                }
                1 -> {
                    LocalDataDao.INSTANCE.getProfile2(itList[i].address)
                }
                else -> {
                    ProfileBean(
                        "MEAT",
                        "", mutableListOf(), singleTemp = false
                    )
                }
            }
            val list = LocalDataDao.INSTANCE.getTempPreAlarmList()
            val currentPreTemp =
                list[LocalDataDao.INSTANCE.getTempPreAlarm(itList[i].address)].preTime.toInt()
            val needResetProfile = LocalDataDao.INSTANCE.hasNeedResetProfile(
                i,
                profile,
                itList.last().address
            )
            println(
                "======> resetProfile  needResetProfile=$needResetProfile currentPreTemp=$currentPreTemp   " +
                        "temp=${itList[i].temperatureNUm} profile=$profile   "
            )
            if (itList[i].temperatureNUm.isNotEmpty() && itList[i].temperatureNUm.toInt() < (profile.highTemperatureNum.toIntOrNull()
                    ?: 0) && needResetProfile && currentPreTemp == 0
            ) {
                println("======> resetProfile  需要")
                when (deviceType) {
                    DeviceListAdapter.VIEW_TYPE_TP960 -> {
                        LocalDataDao.INSTANCE.removeResetProfile(0, itList.last().address)
                        resetProfile(profile, 0, itList.last().address)
                    }
                    else -> {
                        //todo 重新设置目标温度
                    }
                }
            }
        }
    }

    /**
     * 重新设置目标温度
     */
    private fun resetProfile(profileBean: ProfileBean, probeIndex: Int, address: String) {
        val num = (profileBean.highTemperatureNum.toIntOrNull() ?: 0) + 30
        var numStr = Integer.toHexString(num)
        numStr = when (numStr.length) {
            1 -> "0${numStr}00"
            2 -> "${numStr}00"
            3 -> "0${numStr.substring(2, 3)}${numStr.substring(0, 2)}"
            4 -> "${numStr.substring(2, 4)}${numStr.substring(0, 2)}"
            else -> numStr
        }
        val isOpen = if (num == 30) "00" else "01"
        val msg = "040${probeIndex}$isOpen$numStr"
        println("resetProfile msg====$msg")
        val deviceList = BleManager.getInstance().allConnectedDevice.filter { it.mac == address }
        if (deviceList.isNotEmpty()) {
            BleManager.getInstance().write(
                deviceList[0],
                BLUETOOTH_SERVICE_UUID_960,
                BLUETOOTH_WRITE_UUID_960,
                HexUtil.hexStringToBytes(msg),
                object : BleWriteCallback() {
                    override fun onWriteSuccess(
                        current: Int,
                        total: Int,
                        justWrite: ByteArray
                    ) {
                        // 发送数据到设备成功
                        logD(" 蓝牙发送数据成功 resetProfile  $msg")

                    }

                    override fun onWriteFailure(exception: BleException) {
                        logD(" 蓝牙发送数据失败 resetProfile  ${exception.toString()}")
                        // 发送数据到设备失败

                    }
                })
        }
    }


    /**
     * 获取历史数据
     */
    fun getHistoryTP960Temp(address: String, probeIndex: Int) {
        val msg = "020$probeIndex"
        println("getHistoryTemp msg====$msg")
        val deviceList = BleManager.getInstance().allConnectedDevice.filter { it.mac == address }
        if (deviceList.isNotEmpty()) {
            BleManager.getInstance().write(
                deviceList[0],
                TP960ViewModel.BLUETOOTH_SERVICE_UUID_960,
                TP960ViewModel.BLUETOOTH_WRITE_UUID_960,
                HexUtil.hexStringToBytes(msg),
                object : BleWriteCallback() {
                    override fun onWriteSuccess(
                        current: Int,
                        total: Int,
                        justWrite: ByteArray
                    ) {
                        // 发送数据到设备成功
                        logD(" 蓝牙发送数据成功 setProfile  $msg")

                    }

                    override fun onWriteFailure(exception: BleException) {
                        logD(" 蓝牙发送数据失败  ${exception.toString()}")
                        // 发送数据到设备失败

                    }
                })
        }
    }

}